import simpy
import math
import random
import json
import dataclasses

# --- 配置参数 ---
SIM_DURATION = 100.0  # 仿真总时长 (秒)
LOG_INTERVAL = 0.1    # 位置采样间隔 (秒)
NUM_NODES = 3         # 节点数量
C_LIGHT = 3e8         # 光速 (m/s)

# 通信参数
DATA_RATE = 100 * 1024  # 100 KB/s
PACKET_SIZE = 50 * 1024 # 50 KB

class Drone:
    def __init__(self, env, node_id, pos, vel, log_list):
        self.env = env
        self.node_id = node_id
        self.pos = list(pos)
        self.vel = list(vel)
        self.log_list = log_list
        self.env.process(self.move_process())
        self.env.process(self.comm_process())

    def move_process(self):
        """控制移动并定期记录位置"""
        while True:
            self.log_list.append({
                "type": "pos",
                "time": self.env.now,
                "node": self.node_id,
                "pos": list(self.pos)
            })
            dt = LOG_INTERVAL
            self.pos[0] += self.vel[0] * dt
            self.pos[1] += self.vel[1] * dt
            self.pos[2] += self.vel[2] * dt
            yield self.env.timeout(dt)

    def comm_process(self):
        """随机发送数据包"""
        while True:
            yield self.env.timeout(random.uniform(2.0, 5.0))
            targets = [i for i in range(NUM_NODES) if i != self.node_id]
            target_id = random.choice(targets)
            
            # 计算时延
            dist = math.dist(self.pos, nodes[target_id].pos)
            total_delay = (dist / C_LIGHT) + (PACKET_SIZE / DATA_RATE)
            
            packet_id = f"Pkt-{self.node_id}->{target_id}-{int(self.env.now)}"

            # 记录数据包信息
            self.log_list.append({
                "type": "packet",
                "id": packet_id,
                "src": self.node_id,
                "dst": target_id,
                "send_time": self.env.now,
                "arrive_time": self.env.now + total_delay,
                "tag": f"DATA #{int(self.env.now)}" # 用于显示的短标签
            })
            yield self.env.timeout(total_delay)

logs = []
nodes = []

def run_simulation():
    env = simpy.Environment()
    for i in range(NUM_NODES):
        pos = (random.uniform(0, 800), random.uniform(0, 800), random.uniform(50, 300))
        vel = (random.uniform(-15, 15), random.uniform(-15, 15), random.uniform(-5, 5))
        nodes.append(Drone(env, i, pos, vel, logs))
    
    print(f"开始仿真，时长: {SIM_DURATION}s ...")
    env.run(until=SIM_DURATION)
    
    with open("simulation_log.json", "w") as f:
        json.dump(logs, f, indent=2)
    print("数据已保存至 simulation_log.json")

if __name__ == "__main__":
    run_simulation()